package main

// import "math"


//our fitness function
func OurFitness(r []uint64, size int, casesSuccess [][]uint64, casesFailed [][]uint64) (fitValue float64){

	numOfOnesFromPassCases := 0.0
	numOfOnesFromFailedCases := 0.0
	coverFailedCases := 0			// solution 可以解释的失败用例的个数
	oneNums := 0			// solution 包含的1的个数

	for i := 0;i < config.noes;i++ {
		pos := i
		if config.noes % 64 != 0 {
			pos += 64 - config.noes % 64
		}
		found := r[pos / 64] & (1 << uint(63 - (pos % 64)))
		if found > 0{
			oneNums++
			numOfOnesFromFailedCases += float64(config.onesFromFailed[i]) * config.compareValue[i].value
			numOfOnesFromPassCases += float64(config.onesFromPass[i]) * config.compareValue[i].value
		}
	}


	
	// for i := 0; i < len(casesSuccess); i++ {
	// 	for j := 0; j < len(r); j++ {
	// 		buffer := r[j] & casesSuccess[i][j]
	// 		// fmt.Println(i, j, r, casesSuccess[i], buffer)

	// 		for buffer > 0 {
	// 			numOfOnesFromPassCases++
	// 			buffer = buffer & (buffer - 1)
	// 		}
	// 	}
	// }

	
	for i := 0; i < len(casesFailed); i++ {
		for j := 0; j < len(r); j++ {
			buffer := r[j] & casesFailed[i][j]
			if buffer > 0 {
				coverFailedCases++
				break
			}
		}
	}
	
	// for i := 0; i < len(r); i++ {
	// 	buffer := r[i]
	// 	for buffer > 0 {
	// 		oneNums++
	// 		buffer &= (buffer - 1)
	// 	}
	// }

	if numOfOnesFromFailedCases == 0 {
		fitValue = 0
		return
	}
	if coverFailedCases < len(casesFailed) {
		fitValue = 0
		return
	}
	//  numOfOnesFromFailedCases = float64(oneNums) * float64(len(casesFailed)) - float64(numOfOnesFromFailedCases)


	// fitValue = float64(numOfOnesFromFailedCases) /
	// math.Sqrt(
	// 	float64(len(casesFailed)) * float64(numOfOnesFromFailedCases + numOfOnesFromPassCases))
	// fmt.Println(float64(numOfOnesFromFailedCases))
	//fitValue *= math.Sqrt(1 - math.Pow(float64(oneNums) / float64(size), 2)) * 10000
	// fitValue *= math.Pow(0.02, float64(oneNums) / float64(30))
	// fmt.Println(fitValue)
	fitValue = float64(1 + numOfOnesFromFailedCases) / float64(1.0 + numOfOnesFromFailedCases + numOfOnesFromPassCases)
	return
}

//op2Like fitness function
func op2Like(r []uint64, size int, casesSuccess [][]uint64, casesFailed [][]uint64) (fitValue float64) {
	numOfOnesFromFailedCases := 0
	coverFailedCases := 0
	for i := 0; i < len(casesFailed); i++ {
		cover := false
		for j := 0; j < len(r); j++ {
			buffer := r[j] & casesFailed[i][j]
			if buffer > 0 {
				numOfOnesFromFailedCases++
				cover = true
				buffer = buffer & (buffer -1)
				// continue
			}
		}
		if(cover){ coverFailedCases++}
	}
	if coverFailedCases < len(casesFailed) {
		fitValue = 0
		return
	}
	
	fx := 0.0
	px := 0.0
	fx = fx + 1
	px = px + 1
	oneNums := 0
	for i := 0;i < config.noes;i++ {
		pos := i
		if config.noes % 64 != 0 {
			pos += 64 - config.noes % 64
		}
		found := r[pos / 64] & (1 << uint(63 - (pos % 64)))
		if found > 0{
			fx += float64(config.onesFromFailed[i]) // float64(len(config.casesFailed))
			px += float64(config.onesFromPass[i]) // float64(len(config.casesPass))
			oneNums = oneNums + 1
		}
	}
	// fx = fx / float64(oneNums * len(config.casesFailed))
	// px = px / float64(oneNums * len(config.casesPass))
	fitValue = fx - px / float64(oneNums * len(config.casesPass) + 1)
	// fitValue = float64(1 + fx) / float64(1.0 + fx + px)
	// fitValue = float64(fx) / float64(fx + px)
	return
}

//linear fitness function
func LinearFitnessWithCoverAll(r []uint64, size int, casesSuccess [][]uint64, casesFailed [][]uint64) (fitValue float64) {
	numOfOnesFromFailedCases := 0
	coverFailedCases := 0
	for i := 0; i < len(casesFailed); i++ {
		cover := false
		for j := 0; j < len(r); j++ {
			buffer := r[j] & casesFailed[i][j]
			if buffer > 0 {
				numOfOnesFromFailedCases++
				cover = true
				buffer = buffer & (buffer -1)
				// continue
			}
		}
		if(cover){ coverFailedCases++}
	}
	if coverFailedCases < len(casesFailed) {
		fitValue = 0
		return
	}
	
	fx := 0.0
	px := 0.0
	fx = fx + 1
	px = px + 1
	oneNums := 0
	for i := 0;i < config.noes;i++ {
		pos := i
		if config.noes % 64 != 0 {
			pos += 64 - config.noes % 64
		}
		found := r[pos / 64] & (1 << uint(63 - (pos % 64)))
		if found > 0{
			fx += float64(config.onesFromFailed[i]) / float64(len(config.casesFailed))
			px += float64(config.onesFromPass[i]) / float64(len(config.casesPass))
			oneNums = oneNums + 1
		}
	}
	fitValue = float64(1 + fx) / float64(1.0 + fx + px)
	// fitValue = float64(fx) / float64(fx + px)
	return
}

//linear fitness function
func LinearFitness(r []uint64, size int, casesSuccess [][]uint64, casesFailed [][]uint64) (fitValue float64) {
	fx := 0.0
	px := 0.0
	fx = fx + 1
	px = px + 1
	for i := 0;i < config.noes;i++ {
		pos := i
		if config.noes % 64 != 0 {
			pos += 64 - config.noes % 64
		}
		found := r[pos / 64] & (1 << uint(63 - (pos % 64)))
		if found > 0{
			fx += float64(config.onesFromFailed[i]) / float64(len(config.casesFailed))
			px += float64(config.onesFromPass[i]) / float64(len(config.casesPass))
		}
	}
	fitValue = float64(1 + fx) / float64(1.0 + fx + px)
	// fitValue = float64(fx) / float64(fx + px)
	return
}